package com.sdjenkins.exercise.atm;

import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Observable;
import java.util.Observer;

import com.sdjenkins.exercise.atm.ATMCommandProcessor.Command;

/**
 * This is the controller for the ATM and the entry point for the application.
 * 
 * The application uses and MVC pattern.
 * 
 * The init method currently wires up the application and defaults to 
 * Console input and output.
 * 
 * The controller listens for events from the ATMInputOutput object.
 * When and event is fired, the passed parameter is read and converted to a
 * Command object using the ATMCommandInterpreter. The Command Object is then passed to the 
 * ATMCommandProcessor for execution. A message is returned once the command is processed.
 * To display the message, it is then passed back to the ATMInputOutput Object for output. 
 * 
 * @author Simon Jenkins
 *
 */
public class ATMController implements Observer {

	private ATMCommandInterpreter	atmCommandInterpreter;
	private ATMInputOutput 		atmInputOutput;
	private ATMCommandProcessor 	atmCommandProcessor; 
	
	public void update(Observable o, Object arg) {

		if (arg == null) {
			shutdown();
		}
		if (o == atmInputOutput) {
			processComand(arg.toString());			
		}
		else {
			throw new RuntimeException("update error: expected:"+atmInputOutput+" got: "+o);
		}
	}

	private void shutdown() {
		System.exit(0);
	}

	private void processComand(String cmdStr) {
		String returnMessage;
		Command cmd = atmCommandInterpreter.interpret(cmdStr);
		returnMessage = atmCommandProcessor.processCommand(cmd);
		atmInputOutput.output(returnMessage);
	}


	public ATMCommandInterpreter getAtmCommandInterpreter() {
		return atmCommandInterpreter;
	}


	public void setAtmCommandInterpreter(ATMCommandInterpreter atmCommandInterpreter) {
		this.atmCommandInterpreter = atmCommandInterpreter;
	}


	public ATMInputOutput getAtmInputOutput() {
		return atmInputOutput;
	}


	public void setAtmInputOutput(ATMInputOutput atmInputOutput) {
		this.atmInputOutput = atmInputOutput;
	}


	public ATMCommandProcessor getAtmCommandProcessor() {
		return atmCommandProcessor;
	}


	public void setAtmCommandProcessor(ATMCommandProcessor atmCommandProcessor) {
		this.atmCommandProcessor = atmCommandProcessor;
	}
	
	/**
	 * 
	 * Wire up ATM objects in this method for now.
	 *
	 */
	public void init() {
		
		//TODO Replace code with Spring configuration, rather than wiring up in java code
		
		atmCommandProcessor		= new ATMCommandProcessor();
		atmCommandInterpreter 	= new ATMCommandInterpreter();
		atmInputOutput			= new ATMInputOutput();
		atmInputOutput.addObserver(this);
		// Set default io as Console
		atmInputOutput.setReader(new InputStreamReader(System.in));
		atmInputOutput.setWriter(new OutputStreamWriter(System.out));
		
	}
	
}
